/*
 * Created by Wildish on 2016-11-01
 *
 * Contact me with keithknight@qq.com
 *
 * Copyright (c) 2016 Wildish
 */
package com.wildish.hybridframework.utils.file;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class FileUtil {

    public static boolean isFileExists(File file) {
        if (file == null)
            return false;
        return file.exists();
    }

    public static boolean isDirectory(File file) {
        if (file == null)
            return false;
        return file.isDirectory();
    }

    public static boolean isFile(File file) {
        if (file == null)
            return false;
        return file.isFile();
    }

    public static boolean createOrExistsFolder(File file) {
        if (file == null)
            return false;
        boolean result = false;

        if (isFileExists(file) && isDirectory(file)) {
            return true;
        }
        if (file.mkdirs()) {
            result = true;
        } else {
            result = false;
        }
        return result;
    }
    
    public static boolean moveFilesTo(File srcDir, File destDir) {
        if (srcDir == null)
            return false;
        if (destDir == null)
            return false;
        if (!isFileExists(srcDir) || !isDirectory(srcDir)) {
            return false;
        }
        if (!isFileExists(destDir) || !isDirectory(destDir)) {
            if (!createOrExistsFolder(destDir)) {
                return false;
            }
        }
        File[] srcDirFiles = srcDir.listFiles();
        for (int i = 0; i < srcDirFiles.length; i++) {
            if (srcDirFiles[i].isFile()) {
                File oneDestFile = new File(destDir.getPath() + "//"
                        + srcDirFiles[i].getName());
                moveFileTo(srcDirFiles[i], oneDestFile);
                delFile(srcDirFiles[i]);
            } else if (srcDirFiles[i].isDirectory()) {
                File oneDestFile = new File(destDir.getPath() + "//"
                        + srcDirFiles[i].getName());
                moveFilesTo(srcDirFiles[i], oneDestFile);
                delDir(srcDirFiles[i]);
            }
        }
        return true;
    }
    
    public static boolean moveFileTo(File srcFile, File destFile) {
        if (srcFile == null)
            return false;
        if (destFile == null)
            return false;
        boolean iscopy = copyFileTo(srcFile, destFile);
        if (!iscopy)
            return false;
        if (!delFile(srcFile)) {
            return false;
        }
        return true;
    }
    
    public static boolean delFile(File file) {
        if (file == null)
            return false;
        if (!isFileExists(file)) {
            return true;
        }
        if (file.isDirectory())
            return false;
        return file.delete();
    }
    
    public static boolean delDir(File dir) {
        if (dir == null)
            return false;
        if (!isFileExists(dir)) {
            return true;
        }
        if (!isDirectory(dir)) {
            return false;
        }
        for (File file : dir.listFiles()) {
            if (file.isFile()) {
                if (!delFile(file)) {
                    return false;                }
            } else if (file.isDirectory()) {
                if (!delDir(file)) {
                    return false;
                }
            }
        }
        if (!dir.delete()) {
            return false;
        }
        return true;
    }
    
    public static boolean copyFileTo(File srcFile, File destFile) {
        if (srcFile == null)
            return false;
        if (destFile == null)
            return false;
        if (!isFileExists(srcFile)) {
            return false;
        }

        if (!isFile(srcFile)) {
            return false;
        }
        if (isFileExists(destFile) && !isFile(destFile))
            return false;

        File parentFile = destFile.getParentFile();
        if (!createOrExistsFolder(parentFile)) {
            return false;
        }

        FileInputStream fis = null;
        FileOutputStream fos = null;
        boolean result = false;
        try {
            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(destFile);
            int readLen = 0;
            byte[] buf = new byte[1024];
            while ((readLen = fis.read(buf)) != -1) {
                fos.write(buf, 0, readLen);
            }
            fos.flush();
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
            result = false;
        } finally {
            try {
                fos.close();
                fis.close();
            } catch (Exception e) {
                e.printStackTrace();
                result = false;
            }

        }

        return result;
    }

    public static boolean bitmapToFile(Bitmap bitmap, File file){
        if(file == null) {
            return false;
        }
        boolean result = false;
        try{
            if(!file.exists()) {
                file.createNewFile();
            }
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            Bitmap.CompressFormat format = null;
            if(file.getAbsolutePath().endsWith("png")) {
                format = Bitmap.CompressFormat.PNG;
            } else {
                format = Bitmap.CompressFormat.JPEG;
            }
            bitmap.compress(format, 0, bos);
            byte[] bitmapdata = bos.toByteArray();

            FileOutputStream fos = new FileOutputStream(file);
            fos.write(bitmapdata);
            fos.flush();
            fos.close();

            result = true;
        } catch ( Exception e) {
            result = false;
        }
        return result;
    }

    public Bitmap getSmallBitmap(String filePath) {

        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, 480, 800);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;

        Bitmap bm = BitmapFactory.decodeFile(filePath, options);
        if(bm == null){
            return  null;
        }
        int degree = readPictureDegree(filePath);
        bm = rotateBitmap(bm,degree) ;
        ByteArrayOutputStream baos = null ;
        try{
            baos = new ByteArrayOutputStream();
            bm.compress(Bitmap.CompressFormat.JPEG, 70, baos);

        }finally{
            try {
                if(baos != null)
                    baos.close() ;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bm ;

    }

    private static int readPictureDegree(String path) {
        int degree  = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    private static Bitmap rotateBitmap(Bitmap bitmap, int rotate){
        if(bitmap == null)
            return null ;
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        // Setting post rotate to 90
        Matrix mtx = new Matrix();
        mtx.postRotate(rotate);
        return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
    }

    public static void compressImage(File sourceFile, File destFile, int quality) {
        try{
            if(!sourceFile.exists()) {
                return;
            }
            if(sourceFile.getAbsolutePath().toLowerCase().endsWith("jpg") || sourceFile.getAbsolutePath().toLowerCase().endsWith("jpeg")) {
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = false;
                options.inPreferredConfig = Bitmap.Config.RGB_565;
                options.inDither = true;

                Bitmap bmp = decodeSampledBitmap(sourceFile, 768, 1024);
                if(bmp != null) {
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    bmp.compress(Bitmap.CompressFormat.JPEG, quality, bos);

                    FileOutputStream fos = new FileOutputStream(destFile);
                    fos.write(bos.toByteArray());
                    fos.flush();
                    fos.close();
                } else {
                    FileUtil.copyFileTo(sourceFile,destFile);
                }
            } else {
                FileUtil.copyFileTo(sourceFile,destFile);
            }
        } catch (Exception e) {
            e.printStackTrace();
            FileUtil.copyFileTo(sourceFile, destFile);
        }
    }

    public static Bitmap decodeSampledBitmap(File file, int reqWidth, int reqHeight) {

        try{
            // First decode with inJustDecodeBounds=true to check dimensions
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            InputStream is = new FileInputStream(file);
            BitmapFactory.decodeStream(is, null, options);

            options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
            options.inJustDecodeBounds = false;
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            options.inDither = true;

            InputStream is2 = new FileInputStream(file);
            Bitmap result = BitmapFactory.decodeStream(is2, null, options);

            is.close();
            is2.close();
            return result;
        } catch(Exception e) {
        }
        return null;
    }

    public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }

    public static long fileSize(File dir) {
        if (dir.exists()) {
            long result = 0;
            File[] fileList = dir.listFiles();
            for(int i = 0; i < fileList.length; i++) {
                // Recursive call if it's a directory
                if(fileList[i].isDirectory()) {
                    result += fileSize(fileList [i]);
                } else {
                    // Sum the file size in bytes
                    result += fileList[i].length();
                }
            }
            return result; // return the file size
        }
        return 0;
    }
}
